home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Suzy B Software 2
/
Suzy B Software CD-ROM 2 (1994).iso
/
extras
/
programm
/
gemfsc20
/
gemfsc20.lzh
/
GEMFUNCS
/
OBJ_DRAW.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-20
|
20KB
|
687 lines
/*****************************************************************************
* OBJ_DRAW.C - A reentrant objc_draw() that is limited to certain ob_types.
*
* This can do STRINGS, BUTTONS, BOXES, TEXT.
* It cannot do FTEXT, IMAGES, ICONS, or the newer 3D-style objects.
* It can render ob_states of SELECTED, OUTLINED, and DISABLED.
* It cannot do SHADOWED, CHECKED or CROSSED.
*
* A special object type, G_RSTRING is also supported. This is a string
* object that completely replaces an existing string; think of it as a
* bordeless opaque background-filled left-justified BOXTEXT object.
*
* Other than the above limitations, it behaves just like objc_draw. It
* exists primarily to support some of the new extended GemFast objects
* such as the text scroller and numeric slider.
****************************************************************************/
#include "gemfintl.h"
/*----------------------------------------------------------------------------
* constants defining interior, border, and text colors for stock objects.
*--------------------------------------------------------------------------*/
#define DEFAULT_COLORS 0x1180
#define OUTLINED_COLORS 0x0000
#define SELECTED_COLORS 0x0071
#define DISABLED_COLORS 0x0040
static short sysfont_height = 0;
/*----------------------------------------------------------------------------
* internal parm block, passed to all internal functions.
* this is just a bunch of data that all the low-level functions need,
* all glommed together in one structure so we can pass it around quickly.
* (eat your heart out Jim, I still think this is a Good Idea. ::grin::)
*--------------------------------------------------------------------------*/
typedef struct internal_parm_block {
short vhandle; /* handle of VDI shared workstation. */
GRECT gdrawrect; /* rectangle of object currently being rendered. */
VRECT vdrawrect; /* same drawing rectangle, pre-converted to VRECT. */
GRECT gcliprect; /* clipping rectangle specified in objc_draw() call.*/
VRECT vcliprect; /* same clipping rectangle, pre-converted to VRECT. */
short obtype; /* current object's type, w/extended type stripped. */
short color; /* current object's color word. */
short frame_width;/* current object's border width. */
union { /* current object's ob_spec, after processing */
long lval; /* INDIRECT flag (if present). */
char *pstring;/* */
TEDINFO *pted; /* */
XUSERBLK *pub;
} obspec;
} IPB;
/*----------------------------------------------------------------------------
* internal functions...
*--------------------------------------------------------------------------*/
#ifdef GEMFAST_PROTOS
INTERNAL_VFUNC draw_shadow(IPB * pb, short color, short width);
INTERNAL_VFUNC draw_frame(IPB * pb, short color, short width);
INTERNAL_VFUNC draw_interior(IPB * pb, short color);
INTERNAL_VFUNC draw_text(IPB * pb, short color, short justify, short font, char *string);
INTERNAL_VFUNC render_box(IPB * pb);
INTERNAL_VFUNC render_string(IPB * pb);
INTERNAL_VFUNC render_button(IPB * pb);
INTERNAL_VFUNC render_text(IPB * pb);
INTERNAL_IFUNC render_userdef(IPB * pb, OBJECT *ptree, short obj, short prevstate, short currstate);
INTERNAL_VFUNC render_obstate(IPB *pb, short obstate);
INTERNAL_VFUNC render_object(IPB *pb, OBJECT *ptree, short obj, short xoff, short yoff);
INTERNAL_VFUNC render_tree(IPB *pb, OBJECT *ptree, short obj, short depth, short do_siblings, short xoff, short yoff);
INTERNAL_IFUNC special_render_selected_state(OBJECT *ptree, short obj, GRECT *cliprect);
#endif
#if 0 /* de-implement this for now */
INTERNAL_VFUNC draw_shadow(pb, color, width)
IPB * pb;
short color;
short width;
/*----------------------------------------------------------------------------
* draw a shadow under and to the right of an object.
* this doesn't do AES-style shadows, it does real-looking ones. :-)
*--------------------------------------------------------------------------*/
{
short pxy[12];
short x;
short y;
short hbox2;
short wbox2;
short medrez_kludge;
wbox2 = gl_wbox / 2;
hbox2 = gl_hbox / 2;
x = pb->vdrawrect.v_x2;
y = pb->vdrawrect.v_y2;
if (width == 0) {
return;
} else if (width < 0) {
x -= width;
y -= width;
}
if (gl_rfscrn.g_w >= 640 && gl_rfscrn.g_h <= 200) {
medrez_kludge = 3; /* this adjusts for bogus medrez aspect ratio */
} else {
medrez_kludge = 0;
}
pxy[0] = pxy[2] = pb->vdrawrect.v_x1 + wbox2 / 2;
pxy[1] = pxy[11] = y;
pxy[3] = pxy[5] = y + hbox2;
pxy[4] = pxy[6] = x + wbox2 - medrez_kludge;
pxy[7] = pxy[9] = pb->vdrawrect.v_y1 + hbox2 / 2;
pxy[8] = pxy[10] = x;
color >>= 12;
if (color != 1) {
vsf_color(pb->vhandle, color);
}
vswr_mode(pb->vhandle, MD_TRANS);
vsf_interior(pb->vhandle, IS_PATTERN);
vsf_style(pb->vhandle, 4);
vsf_perimeter(pb->vhandle, FALSE);
v_fillarea(pb->vhandle, 6, pxy); /* draw L-shaped shadow */
vswr_mode(pb->vhandle, MD_REPLACE);
vsf_interior(pb->vhandle, IS_SOLID);
vsf_style(pb->vhandle, 8);
vsf_perimeter(pb->vhandle, TRUE);
if (color != 1) {
vsf_color(pb->vhandle, 1);
}
}
#endif /* end of de-implemented shadow rendering */
INTERNAL_VFUNC draw_frame(pb, color, width)
IPB * pb;
short color;
short width;
/*----------------------------------------------------------------------------
* draw a frame (ibox) of a given line width.
*--------------------------------------------------------------------------*/
{
short pxy[10];
short adjust;
short direction;
if (width == 0) {
return;
} else if (width < 0) {
direction = 1;
adjust = width;
} else {
direction = -1;
adjust = width - 1;
}
color >>= 12;
if (color != 1) {
vsl_color(pb->vhandle, color);
}
while (width) {
pxy[0] = pxy[6] = pxy[8] = pb->vdrawrect.v_x1 + adjust;
pxy[1] = pxy[3] = pxy[9] = pb->vdrawrect.v_y1 + adjust;
pxy[2] = pxy[4] = pb->vdrawrect.v_x2 - adjust;
pxy[5] = pxy[7] = pb->vdrawrect.v_y2 - adjust;
v_pline(pb->vhandle, 5, pxy);
adjust += direction;
width += direction;
}
if (color != 1) {
vsl_color(pb->vhandle, 1);
}
}
INTERNAL_VFUNC draw_interior(pb, color)
IPB * pb;
short color;
/*----------------------------------------------------------------------------
* draw the interior of a box.
*--------------------------------------------------------------------------*/
{
short style;
style = (color >> 4) & 0x0007;
color &= 0x000F;
if (color != 1) {
vsf_color(pb->vhandle, color);
}
switch (style) {
case 0:
vsf_interior(pb->vhandle, IS_HOLLOW);
break;
case 7:
break; /* style 7 is the default already set on the workstation */
default:
vsf_interior(pb->vhandle, IS_PATTERN);
vsf_style(pb->vhandle, style);
break;
}
vr_recfl(pb->vhandle, (short *)&pb->vdrawrect);
if (color != 1) {
vsf_color(pb->vhandle, 1);
}
if (style != 7) {
vsf_interior(pb->vhandle, IS_SOLID);
vsf_style(pb->vhandle, 8);
}
}
INTERNAL_VFUNC draw_text(pb, color, justify, font, string)
IPB * pb;
short color;
short justify;
short font;
char *string;
/*----------------------------------------------------------------------------
* draw some text; will clip text to object's boundaries.
*--------------------------------------------------------------------------*/
{
short mode;
short wchar;
short hchar;
short textwidth;
short dmy;
short x;
short y;
GRECT gcliprect;
VRECT vcliprect;
mode = color & 0x0080;
color = (color >> 8) & 0x000F;
if (color != 1) {
vst_color(pb->vhandle, color);
}
if (mode == 0) {
vswr_mode(pb->vhandle, MD_TRANS);
}
if (font == TE_SMALL) {
vst_height(pb->vhandle, 4, &wchar, &hchar, &dmy, &dmy);
} else {
wchar = gl_wchar;
hchar = gl_hchar;
}
textwidth = wchar * (short)strlen(string);
switch (justify) {
case TE_LEFT:
x = pb->gdrawrect.g_x;
break;
case TE_RIGHT:
x = pb->gdrawrect.g_x + (pb->gdrawrect.g_w - textwidth);
break;
case TE_CNTR:
x = pb->gdrawrect.g_x + ((pb->gdrawrect.g_w - textwidth) / 2);
break;
}
y = pb->gdrawrect.g_y + ((pb->gdrawrect.g_h - hchar) / 2);
vst_alignment(pb->vhandle, 0, 5, &dmy, &dmy);
gcliprect = pb->gcliprect;
if (rc_intersect(&pb->gdrawrect, &gcliprect)) {
rc_gtov(&gcliprect, &vcliprect);
vs_clip(pb->vhandle, TRUE, (short *)&vcliprect);
v_gtext(pb->vhandle, x, y, string);
vs_clip(pb->vhandle, TRUE, (short *)&pb->vcliprect);
}
vst_alignment(pb->vhandle, 0, 0, &dmy, &dmy);
if (color != 1) {
vst_color(pb->vhandle, 1);
}
if (mode == 0) {
vswr_mode(pb->vhandle, MD_REPLACE);
}
if (font == TE_SMALL) {
vst_height(pb->vhandle, sysfont_height, &dmy, &dmy, &dmy, &dmy);
}
}
INTERNAL_VFUNC render_box(pb)
IPB * pb;
/*----------------------------------------------------------------------------
* render a box, ibox, or boxchar object.
*--------------------------------------------------------------------------*/
{
char str[2];
if (pb->obtype != G_IBOX) {
draw_interior(pb, pb->color);
}
if (pb->obtype == G_BOXCHAR) {
str[0] = (char)(pb->obspec.lval >> 24);
str[1] = 0;
draw_text(pb, pb->color, TE_CNTR, TE_SYSTEM, str);
}
draw_frame(pb, pb->color, pb->frame_width);
}
INTERNAL_VFUNC render_string(pb)
IPB * pb;
/*----------------------------------------------------------------------------
* render a string or title object.
*--------------------------------------------------------------------------*/
{
if (pb->obtype == G_RSTRING) { /* special object: replace string,*/
draw_interior(pb, DEFAULT_COLORS); /* it's like a borderless boxtext;*/
} /* erases existing string. */
draw_text(pb, DEFAULT_COLORS, TE_LEFT, TE_SYSTEM, pb->obspec.pstring);
}
INTERNAL_VFUNC render_button(pb)
IPB * pb;
/*----------------------------------------------------------------------------
* render a button object.
*--------------------------------------------------------------------------*/
{
draw_interior(pb, DEFAULT_COLORS);
draw_text(pb, DEFAULT_COLORS, TE_CNTR, TE_SYSTEM, pb->obspec.pstring);
draw_frame(pb, DEFAULT_COLORS, pb->frame_width);
}
INTERNAL_VFUNC render_text(pb)
IPB * pb;
/*----------------------------------------------------------------------------
* render a text or boxtext (but not ftext or fboxtext) object.
*--------------------------------------------------------------------------*/
{
TEDINFO *pted = pb->obspec.pted;
if (pb->obtype == G_BOXTEXT) {
draw_interior(pb, pb->color);
}
draw_text(pb, pb->color, pted->te_just, pted->te_font, pted->te_ptext);
if (pb->obtype == G_BOXTEXT) {
draw_frame(pb, pb->color, pb->frame_width);
}
}
INTERNAL_IFUNC render_userdef(pb, ptree, obj, prevstate, currstate)
IPB * pb;
OBJECT *ptree;
short obj;
short prevstate;
short currstate;
/*----------------------------------------------------------------------------
* render a userdef object, return unrendered-state info from user draw func.
*--------------------------------------------------------------------------*/
{
XPARMBLK xpb; /* a standard PARMBLK with sensibly-typed fields */
xpb.ptree = ptree;
xpb.obj = obj;
xpb.prevstate = prevstate;
xpb.currstate = currstate;
xpb.drawrect = pb->gdrawrect;
xpb.cliprect = pb->gcliprect;
xpb.pub = pb->obspec.pub;
return (int)(*pb->obspec.pub->ub_draw)(&xpb);
}
INTERNAL_VFUNC render_obstate(pb, obstate)
IPB * pb;
short obstate;
/*----------------------------------------------------------------------------
* render the object state effects.
*--------------------------------------------------------------------------*/
{
if (obstate & OUTLINED) {
draw_frame(pb, DEFAULT_COLORS, -3);
draw_frame(pb, OUTLINED_COLORS, -2);
}
/* if (obstate & SHADOWED) { */
/* draw_shadow(pb, pb->color, pb->frame_width); */
/* } */
if (obstate & SELECTED) {
vswr_mode(pb->vhandle, MD_XOR);
draw_interior(pb, SELECTED_COLORS);
vswr_mode(pb->vhandle, MD_REPLACE);
}
if (obstate & DISABLED) {
vswr_mode(pb->vhandle, MD_ERASE);
draw_interior(pb, DISABLED_COLORS);
vswr_mode(pb->vhandle, MD_REPLACE);
}
if (obstate & CHECKED) { /* really should do this one next */
}
if (obstate & CROSSED) { /* everyone's favorite state */
}
}
INTERNAL_VFUNC render_object(pb, ptree, obj, xoff, yoff)
IPB * pb;
OBJECT *ptree;
short obj;
short xoff;
short yoff;
/*----------------------------------------------------------------------------
* render a single object of any (currently supported) type.
*--------------------------------------------------------------------------*/
{
OBJECT *pobj;
short obstate;
pobj = &ptree[obj];
obstate = pobj->ob_state;
pb->gdrawrect.g_x = pobj->ob_x + xoff;
pb->gdrawrect.g_y = pobj->ob_y + yoff;
pb->gdrawrect.g_w = pobj->ob_width;
pb->gdrawrect.g_h = pobj->ob_height;
rc_gtov(&pb->gdrawrect, &pb->vdrawrect);
if (pobj->ob_flags & INDIRECT) {
pb->obspec.lval = *(long*)pobj->ob_spec;
} else {
pb->obspec.lval = (long)pobj->ob_spec;
}
pb->frame_width = 0;
pb->color = DEFAULT_COLORS;
pb->obtype = pobj->ob_type & 0x00FF;
switch (pb->obtype) {
case G_BOX:
case G_IBOX:
case G_BOXCHAR:
pb->frame_width = (char)(pb->obspec.lval >> 16);
pb->color = (short)(pb->obspec.lval & 0x0000FFFF);
render_box(pb);
break;
case G_TEXT:
case G_BOXTEXT:
pb->frame_width = pb->obspec.pted->te_thickness;
pb->color = pb->obspec.pted->te_color;
render_text(pb);
break;
case G_BUTTON:
pb->frame_width = -1;
if (pobj->ob_flags & EXIT) {
--pb->frame_width;
if (pobj->ob_flags & DEFAULT) {
--pb->frame_width;
}
}
render_button(pb);
break;
case G_TITLE:
case G_STRING:
case G_RSTRING:
render_string(pb);
break;
case G_USERDEF:
obstate = render_userdef(pb, ptree, obj, obstate, obstate);
break;
}
render_obstate(pb, obstate);
}
INTERNAL_VFUNC render_tree(pb, ptree, obj, depth, do_siblings, xoff, yoff)
IPB * pb;
OBJECT *ptree;
short obj;
short depth;
short do_siblings;
short xoff;
short yoff;
/*----------------------------------------------------------------------------
* render all objects in the tree/subtree, recursing to specified depth.
*--------------------------------------------------------------------------*/
{
OBJECT *pobj;
short nxtobj;
do {
pobj = &ptree[obj];
if (!(pobj->ob_flags & HIDETREE)) {
render_object(pb, ptree, obj, xoff, yoff);
nxtobj = pobj->ob_head;
if (depth > 1 && nxtobj != NO_OBJECT) {
render_tree(pb, ptree, nxtobj, depth-1, TRUE,
xoff+ptree[obj].ob_x, yoff+ptree[obj].ob_y);
}
}
if (!do_siblings) {
obj = NO_OBJECT;
} else {
nxtobj = pobj->ob_next;
if (nxtobj == NO_OBJECT || ptree[nxtobj].ob_tail == obj) {
obj = NO_OBJECT;
} else {
obj = nxtobj;
}
}
} while (obj != NO_OBJECT);
}
INTERNAL_IFUNC special_render_selected_state(ptree, obj, cliprect)
OBJECT *ptree;
short obj;
GRECT *cliprect;
/*----------------------------------------------------------------------------
* render a change in the SELECTED state.
* this is a special speedup kludge for obj__change(). the state most
* often changed is SELECTED, and for things like menu displays our
* standard logic of erasing and redrawing the object is a bit slow; the
* visual effect isn't very pleasing. so, if the only state being
* changed on an obj__change call is SELECTED, we come here and XOR the
* object's interior quickly, instead of using the erase-and-redraw logic.
*--------------------------------------------------------------------------*/
{
IPB pb;
if (0 == (pb.vhandle = apl_vshared())) {
return FALSE;
}
obj_offxywh(ptree, obj, &pb.gdrawrect);
rc_gtov(&pb.gdrawrect, &pb.vdrawrect);
pb.gcliprect = *cliprect;
if (rc_intersect(&gl_rfscrn, &pb.gcliprect)) {
rc_gtov(&pb.gcliprect, &pb.vcliprect);
v_hide_c(pb.vhandle);
vs_clip(pb.vhandle, TRUE, (short *)&pb.vcliprect);
vswr_mode(pb.vhandle, MD_XOR);
draw_interior(&pb, SELECTED_COLORS);
vswr_mode(pb.vhandle, MD_REPLACE);
vs_clip(pb.vhandle, FALSE, (short *)&pb.vcliprect);
v_show_c(pb.vhandle, TRUE);
}
return TRUE;
}
/*----------------------------------------------------------------------------
* public functions...
*--------------------------------------------------------------------------*/
int obj__offset(ptree, obj, px, py)
OBJECT *ptree;
short obj;
short * px;
short * py;
/*****************************************************************************
* return screen-adjusted object coordinates.
****************************************************************************/
{
short x = 0;
short y = 0;
while (obj != ROOT) {
x += ptree[obj].ob_x;
y += ptree[obj].ob_y;
obj = obj_parent(ptree, obj);
}
*px = x + ptree->ob_x;;
*py = y + ptree->ob_y;
return TRUE;
}
short obj__draw(ptree, obj, depth, cliprect)
OBJECT *ptree;
short obj;
short depth;
GRECT * cliprect;
/*****************************************************************************
* draw object tree, as per AES function objc_draw().
****************************************************************************/
{
IPB pb;
short xoff, yoff;
if (0 == (pb.vhandle = apl_vshared())) {
return FALSE;
}
if (sysfont_height == 0) {
short attr[10];
vqt_attributes(pb.vhandle, attr);
sysfont_height = attr[7];
}
pb.gcliprect = *cliprect;
if (obj == ROOT) {
xoff = yoff = 0;
} else {
objc_offset(ptree, obj_parent(ptree, obj), &xoff, &yoff);
}
if (rc_intersect(&gl_rfscrn, &pb.gcliprect)) {
rc_gtov(&pb.gcliprect, &pb.vcliprect);
v_hide_c(pb.vhandle);
vs_clip(pb.vhandle, TRUE, (short *)&pb.vcliprect);
render_tree(&pb, ptree, obj, depth, FALSE, xoff, yoff);
vs_clip(pb.vhandle, FALSE, (short *)&pb.vcliprect);
v_show_c(pb.vhandle, TRUE);
}
return TRUE;
}
int obj__change(ptree, obj, reserved, cliprect, newstate, redraw)
OBJECT *ptree;
short obj;
short reserved;
GRECT * cliprect;
short newstate;
short redraw;
/*****************************************************************************
* change an object's ob_state, with optional redraw.
* this does NOT work like the AES's equivelent function. this one
* always redraws the object in its entirety. in addition, the redraw
* starts with the object's parent and is clipped such that the bits
* outside the object (ie, OUTLINED and SHADOWED) are properly redrawn.
*
* if the only state being changed is SELECTED, we use special logic to
* quickly XOR the object's interior instead of using the erase-and-redraw
* logic. this gives a better visual effect on things like menus where
* the SELECTED state is changed rapidly while tracking the mouse.
****************************************************************************/
{
short oldstate;
GRECT userclip;
GRECT objclip;
oldstate = ptree[obj].ob_state;
ptree[obj].ob_state = newstate;
if (!redraw || oldstate == newstate) {
return TRUE;
}
if ((oldstate ^ newstate) == SELECTED) {
return special_render_selected_state(ptree, obj, cliprect);
}
userclip = *cliprect;
obj_clcalc(ptree, obj, &objclip, NULL);
if (rc_intersect(&userclip, &objclip)) {
obj = obj_parent(ptree, obj);
return objc_draw(ptree, obj, MAX_DEPTH, RECTVALS(&objclip));
}
}